package com.jiangruan.javaproject.address;/**
 * @author:xulonghua
 * @email:3162193565@qq.com desc:
 * datatime 2021/12/20 22:33
 */


import com.jiangruan.javaproject.utils.Base58;
import com.jiangruan.javaproject.utils.Hash;

import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECPoint;

/**
 *@author:xulonghua
 *@email:3162193565@qq.com
 *desc:该类用于生成比特币的地址
 *datetime 2021/12/20 22:33
 */
public class Address {
    /**
     * java中原生，生成一对密钥，并将密钥对对象KeyPair返回
     *@return keyPair
     */

    public  KeyPair generateKey(){
        try {
            KeyPairGenerator generator= KeyPairGenerator.getInstance ( "EC" );
            //secp256k1,secp256r1
            ECGenParameterSpec spec=new ECGenParameterSpec ( "secp256k1" );
            generator.initialize ( spec);
            //生成一对密钥
            return  generator.generateKeyPair ();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace ();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace ();
        }
        return  null;
    }/**
     *根据提供的密钥对数据推导生成一个原始格式的比特币地址，并返回
     * @param keyPair 提供的密钥对信息
     * @return 推到生成的比特币地址
     */
    public String newAddress(KeyPair keyPair){
        if (keyPair==null){
            return null;
        }
        ECPublicKey publicKey=(ECPublicKey) keyPair.getPublic ();
        //原始格式公钥 ：04 +x 坐标（32字节）+坐标（32字节）
       ECPoint point= publicKey.getW ();
     byte[] xBytes = point.getAffineX ().toByteArray ();
     byte[] yBytes = point.getAffineY ().toByteArray ();
     byte[] pubKey=toUncompressPubKey ( xBytes,yBytes );
       // System.out.println (pubKey.length);

        byte[] sha256=Hash.SHA256 ( pubKey );
        //公钥哈希
        byte[] pubHash=Hash.PRPEMD160 ( sha256 );

        //添加前缀
        byte[] version =new byte[1];
        version[0]=0x00;
        byte[] ver_pubhash =new byte[version.length+pubHash.length];
        System.arraycopy ( version,0,ver_pubhash,0,version.length );
        System.arraycopy ( pubHash,0,ver_pubhash,1,pubHash.length );
        //双哈希，去校验位
        byte[] hash1=Hash.SHA256 ( ver_pubhash );
        byte[] hash2=Hash.SHA256 ( hash1 );
        byte[] check=new byte[4];
        System.arraycopy (hash2,0,check,0,4);
        byte[] ver_pubhash_check=new byte[ver_pubhash.length+check.length];
        //System.out.println (ver_pubhash_check.length);
        System.arraycopy ( ver_pubhash,0,ver_pubhash_check,0,ver_pubhash.length );
        System.arraycopy ( check ,0,ver_pubhash_check,ver_pubhash.length,check.length);
        //base58编码
        String addre=Base58.encode ( ver_pubhash_check );

        System.out.println (addre);
        return addre;
    }
    /**
    *该方法根据x坐标和y坐标数据，用于拼接生成原始数据的公钥
    * @param x x坐标数据
    * @param y y 坐标数据
    * @return 原始格式的公钥
    */
private  static  byte[] toUncompressPubKey(byte[] x,byte[] y){
        //原始格式公钥：04+x坐标（32字节）+y坐标（32字节）
    byte[] PublicKey=new byte[65];
    PublicKey[0]=04;
    if (x.length==32){
        //将x坐标全部拷贝到创建的原始格式公钥中去
        System.arraycopy ( x,0,PublicKey,1,x.length );
    }else if (x.length >32){
        System.arraycopy ( x,1,PublicKey,1,32 );
    }
    if (y.length ==32){
        System.arraycopy ( y,0,PublicKey,33,y.length );
    }else if (y.length >32){
        System.arraycopy ( y,1,PublicKey,33, 32);
    }
    return PublicKey;
}
}
